#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<stdbool.h>
#include<pthread.h>
#include<semaphore.h>

typedef struct RingQueue
{
    int a[100];
    int N;
    int n;
    int pi;
    int ci;
    sem_t space;
    sem_t data;;
    pthread_mutex_t mtx;
}RingQueue;

void RingQueue_Init(RingQueue* rq)
{
    rq->N = 10;
    rq->n = 0;
    rq->pi = 0;
    rq->ci = 0;
    sem_init(&(rq->space), 0, rq->N);
    sem_init(&(rq->data), 0, 0);

    pthread_mutex_init(&(rq->mtx), NULL);
}

bool RingQueue_Empty(RingQueue* rq)
{
    return rq->n == 0;
}

bool RingQueue_Full(RingQueue* rq)
{
    return rq->n == rq->N;
}

void RingQueue_Push(RingQueue* rq, int in)
{
    sem_wait(&(rq->space));
    pthread_mutex_lock(&(rq->mtx));

    rq->a[rq->pi++] = in;
    rq->pi %= rq->N;
    rq->n++;
    pthread_mutex_unlock(&(rq->mtx));
    sem_post(&(rq->data));
}

void RingQueue_Pop(RingQueue* rq, int* out)
{
    sem_wait(&(rq->data));

    pthread_mutex_lock(&(rq->mtx));

    *out = rq->a[rq->ci++];
    rq->ci %= rq->N;
    rq->n--;

    pthread_mutex_unlock(&(rq->mtx));

    sem_post(&(rq->space));

}

void RingQueue_Destroy(RingQueue* rq)
{
    pthread_mutex_destroy(&(rq->mtx));
    sem_destroy(&(rq->space));
    sem_destroy(&(rq->data));
}

void* productor(void* args)
{
    RingQueue* prq = (RingQueue*)args;
    int i = 0;
    while(1)
    {
        sleep(1);
        RingQueue_Push(prq, i);
        printf("已生产了一个数据: %d\n", i);
        ++i;
    }
    return NULL;
}

void* consumer(void* args)
{
    RingQueue* prq = (RingQueue*)args;
        
    printf("void* consumer(void* argvs)\n");
    while(1)
    {
        int out = 0;
        RingQueue_Pop(prq, &out);
        printf("已消费了一个数据: %d\n", out);
        sleep(1);
    }
    return NULL;

}

int main()
{
    RingQueue* prq = (RingQueue*)malloc(sizeof(RingQueue));
    RingQueue_Init(prq);
    pthread_t pt;
    pthread_t ct;
    pthread_create(&pt, NULL, productor, (void*)prq);
    pthread_create(&ct, NULL, consumer, (void*)prq);



    pthread_join(pt, NULL);
    pthread_join(ct, NULL);

    // pthread_t pt[3];
    // for(int i = 0; i < 3; ++i)
    // {
    //     pthread_create(pt+i, NULL, productor, (void*)prq);

    // }

    // pthread_t ct[3];
    // for(int i = 0; i < 3; ++i)
    // {
    //     pthread_create(ct+i, NULL, consumer, (void*)prq);

    // }
    
    // for(int i = 0; i < 3; ++i)
    // {
    //     pthread_join(pt[i], NULL);
    // }
    // for(int i = 0; i < 3; ++i)
    // {
    //     pthread_join(ct[i], NULL);
    // }

    RingQueue_Destroy(prq);
    free(prq);

    return 0;
}
